#pragma once

// system include
#include <iostream>
#include <random>
#include <sstream>
#include <stdexcept>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstring>
#include <functional>
#include <map>

// Qt include
#include "QtWidgets/QtWidgets"
#include "QtWidgets/QMainWindow"
#include "QtWidgets/QListWidget"
#include "QtWidgets/QListWidgetItem"
#include "QtWidgets/QFileDialog"
#include "QtWidgets/QInputDialog"
#include "QtCore/QStringList"

// carla include
#include "carla/client/Client.h"
#include "carla/trafficmanager/TrafficManager.h"
#include "carla/client/BlueprintLibrary.h"
#include "carla/client/Map.h"
#include "carla/client/World.h"
#include "carla/image/ImageIO.h"
#include "carla/image/ImageView.h"
#include "carla/sensor/data/Image.h"
#include "carla/client/Sensor.h"
#include "carla/road/Signal.h"
#include "carla/client/ActorList.h"
#include "carla/rpc/ActorAttribute.h"

// glog include
#include "glog/logging.h"

// GUI include
#include "ui/Ui_MainWidget.h"

class MainWindow: public QMainWindow
{
    // Q_OBJECT
public:
    /* 成员变量 */
    MainWindow(QWidget* parent = nullptr);
    ~MainWindow();

    /**
     * @brief Set the Current Ego Car object
     * 
     */
    void SetCurrentEgoCar();

    /**
     * @brief Get the Current Ego Car Env
     * 
     */
    void GetCurrentEgoCarEnv();

protected:
    /* 成员函数 */
    void _Init();
    void _DeInit();
    void _WriteToFile(const std::string& file_name, const std::string& file_text);
    uint64_t _GetNowTimeCount();
    void _EchoAndSave(const std::stringstream& s_stream, const std::string& file_name);
    int _ReadFile(const std::string& file_path, std::stringstream& file_context);
    
    /**
     * @brief 加载 OpenDrive 地图
     * 
     */
    void _GenerateOpenDriveWorld();

    /**
     * @brief 获取并显示建议的出生点
     * 
     */
    void _GetAndShowRecommendedSpawnPoints();

    /**
     * @brief 在指定的出生点放置一个车辆
     * 
     */
    void _SpawnACarInSelectedPoint();

    /**
     * @brief 清除所有已经放置的车辆
     * 
     * @return 
     */
    void _DestoryAllCar();

    /**
     * @brief 选择一个 Transfor 创建车辆
     * 
     */
    void _SpawnACarInTargetTransform();

    /**
     * @brief 创建一个车辆，并拿到创建的车辆
     * 
     * @param spawn_point 要放置的车辆位置
     * @return boost::shared_ptr<carla::client::Vehicle> 
     */
    boost::shared_ptr<carla::client::Vehicle> _CreateACar(const carla::geom::Transform& spawn_point);

    /**
     * @brief 获取当前所有的 Actor 信息
     * 
     */
    void _GetAllActorsInfo();

    /* 成员变量 */
    std::shared_ptr<carla::client::Client> _carlaClient;
    std::shared_ptr<carla::client::World> _carlaWorld;
    carla::SharedPtr<carla::client::Map> _carlaMap;
    std::shared_ptr<std::vector<carla::geom::Transform>> _recommandSpawnPoints;
    boost::shared_ptr<carla::client::Vehicle> _currentEgoCar;

protected slots:
    void _SlotOnPushButtonClicked();
    void _SlotOnListWidgetItemDoubleClicked(QListWidgetItem* item);
    void _SlotOnListWidgetItemPressed(QListWidgetItem* item);

private:
    Ui::MainWindow ui;
};